namespace FIREFLYX {
    /** 方差阴影图 着色器*/
    export const BUILTIN_SHADER_VSM = `VarianceShadowMap`;
    DefaultAsset.shaderGenMap[BUILTIN_SHADER_VSM] = () => {
        const vsCode = `#version 300 es
            precision highp float;
            precision highp int;
            layout (location = 0) in vec4 a_Position; //顶点 位置 是有默认值的 (0,0,0,1)
            layout (location = 3) in vec2 a_UV;       //UV 纹理坐标
            out vec2 v_uv;
            void main() {
                v_uv = a_UV;
                vec4 pos = vec4(a_Position.xyz , 1.0);
                gl_Position = pos;
            }
        `;

        const fsCode = `#version 300 es
            precision mediump float;

            uniform sampler2D u_mainTex;
            uniform vec2 u_resolution;              //画布分辨率
            uniform float u_radius;                 //采样半径
            uniform float u_samples;                //采样次数
            uniform float u_horizontalPass;         //是否水平方向
            
            in vec2 v_uv;
            out vec4 color;

            vec4 pack2HalfToRGBA( vec2 v ) {
                vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );
                return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );
            }
            vec2 unpackRGBATo2Half( vec4 v ) {
                return vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );
            }

            void main(){
                //vsm calc
                float samples = u_samples;
                float mean = 0.0;
                float squared_mean = 0.0;
                float uvStride = samples <= 1.0 ? 0.0 : 2.0 / (samples - 1.0);
                float uvStart = samples <= 1.0 ? 0.0 : -1.0;
                for(float i = 0.0; i < samples; i++) {
                    float uvOffset = uvStart + i * uvStride;
                    if(u_horizontalPass == 1.0){
                        //水平方向计算
                        vec2 distribution = unpackRGBATo2Half( texture( u_mainTex, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * u_radius ) / u_resolution) );
                        mean += distribution.x;
                        squared_mean += distribution.y * distribution.y + distribution.x * distribution.x;
                    }else{
                        //垂直方向计算
                        float depth = texture(u_mainTex, (gl_FragCoord.xy + vec2(0.0, uvOffset) * u_radius) / u_resolution).r;
                        mean += depth;
                        squared_mean += depth * depth;
                    }
                }
                mean = mean / samples;
                squared_mean = squared_mean / samples;
                float std_dev = sqrt(squared_mean - mean * mean);
                color = pack2HalfToRGBA(vec2(mean, std_dev));
            }
        `;
        //glsl
        const vs = new GLSL();
        vs.setCode(vsCode);
        const fs = new GLSL();
        fs.setCode(fsCode);

        //shader
        let result: Shader = new Shader();
        result.tag = BUILTIN_SHADER_VSM;
        result.lightMode = RenderPipeline.LM_SHADOW_CASTER;
        result.vertexGLSL = vs;
        result.fragmentGLSL = fs;
        //unifrom 默认值
        result.definePropertyMap = {};

        result.definePropertyMap.u_radius = {
            type: "float",
            value: 1,
        };

        //apply
        result.apply();

        return result;
    };
}